home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
csrc1.arc
/
COOBLD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-07-27
|
13KB
|
553 lines
#
/*
* coobld
*
*/
/*)BUILD
*/
#ifdef DOCUMENTATION
title coobld Build Cookie Data File
index Build cookie data file
synopsis
coobld [options] file_list
description
Build the internal data file for fortune cookies.
If no file argument is given, the file "cookie.txt"
will be looked for on the current account. The file_list
may contain wild-cards.
.s
The following options are defined:
.lm +8
.s.i -8;-d Debug
.s.i -8;-v Verify (print each cookie line as it is read)
Cookie File Format
Cookie text files have the following format:
.nf
Each cookie is terminated by a line containing
"%%" in column 1 and 2.
%%
By default, a cookie that starts with one
or more spaces is considered to be a "poem"
and will not be reformatted.
%%
To attribute a cookie. terminate it by
terminating the sentence with a '.', '?',
or '!' then append the author's name as shown.
-- Author's name.
It is recommended that author's names start in
column 48 where possible. Note that the cookie
may continue, which allows adding footnotes or
rebuttals.
%%
.s.f
Cookies are stored on a disk file in a format compatible
with the limited amount of random access capabilities available
on "standard" C libraries. The format is, of course, called
"Cookie access method." The output file is written by fwrite()
and must be read by fread().
.s
The cookie file has the following format:
.s.nf
Record 1:
long ncookie; /* number of cookies */
int nindex; /* Index table size */
int subindex; /* How many subindexes */
int sindex; /* sizeof index table */
char date[26]; /* When file created */
.s
Record 2:
long main_index[tabdim];
/* Seek location for */
/* each subindex entry */
.s
Record 3 .. tabdim+2
long sub_index[tabdim];
/* Cookie seek address */
.s
Cookie records have just plain text, one space between words.
Each cookie is terminated by a line containing "%%".
.s
Thus, to find cookie N, proceed as follows:
.s.nf
Read record 1.
Allocate space for index[].
Read record 2 into index.
.s
Read index[N / ncookies] into index.
Read from index[N % ncookies].
.s.f
Note: if the maximum cookie contains 2047 bytes, the index table
may be dimensioned (2047 / sizeof (long)) (== 256) and the maximum
number of cookies equals 256 * 256 == 65536. If this is done, and
only one cookie is to be read, only one buffer is needed, defined as:
.s.nf
union {
char text[TEXTSIZE];
long index[TEXTSIZE / sizeof (long)];
} cookie;
author
Martin Minow
bugs
probably.
#endif
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define EOS 0
#ifdef rsx
#define R_MODE "run"
#define W_MODE "wun"
#else
#ifdef rt11
#define R_MODE "rn"
#define W_MODE "wn"
#else
#define R_MODE "r"
#define W_MODE "w"
#endif
#endif
#define SIGNAL '%'
extern long ftell();
FILE *indexfp; /* Indexes stored here */
FILE *dummyfp; /* Dummy output file */
FILE *outfp; /* Output file (cookie.fil) */
#define INPUT_FILE "cookie.txt"
/*
* The following may need work on RT11 to insert file sizes
*/
char *text_file = "ctext.tmp";
char *dummy_file = "cdummy.tmp";
char *index_file = "cindex.tmp";
char *cookie_file = "cookie.fil";
struct header {
long ncookie; /* Number of cookies */
int nindex; /* Dimension of top_index[] */
int subindex; /* Number of subindex entries */
int sindex; /* Sizeof index for alloc */
char date[28]; /* Date cookie file built */
} header;
char text[513]; /* Working text */
long *sub_index; /* Indexes stored here */
long *top_index; /* Top level indexes go here */
long firstindex; /* -> top index in indexfp */
long firstcookie; /* -> first cookie in dummyfp */
int verbose = 0;
int debug = 0;
main(argc, argv)
int argc;
char *argv[];
{
register char *ap;
register int i;
int nfiles;
FILE *file_open();
nfiles = 0;
for (i = 1; i < argc; i++) {
ap = argv[i];
if (*ap++ == '-') {
argv[i] = NULL;
for (; *ap != EOS; ap++) {
switch (tolower(*ap)) {
case 'd':
debug++;
break;
case 'v':
verbose++;
break;
default:
fprintf(stderr, "?Unknown option '%c'\n", *ap);
}
}
}
else {
nfiles++;
}
}
/*
* Copy raw cookies to a temp file. Collect how many and
* dimension of indexes.
*/
if (nfiles == 0) {
argc = 2;
argv[1] = INPUT_FILE;
}
maketext(argc, argv);
/*
* Build dummy cookie file
*/
dummyfp = file_open(dummy_file, W_MODE);
indexfp = file_open(index_file, W_MODE);
makedummy(argc, argv);
fclose(dummyfp);
fclose(indexfp);
/*
* Build real cookie file
*/
outfp = file_open(cookie_file, W_MODE);
dummyfp = file_open(dummy_file, R_MODE);
indexfp = file_open(index_file, R_MODE);
makecookie();
fclose(outfp);
cdelete(dummyfp);
cdelete(indexfp);
}
cdelete(fd)
FILE *fd;
/*
* Close or delete the file
*/
{
char work[40];
if (debug)
fclose(fd);
else {
fgetname(fd, work);
fclose(fd);
delete(work);
}
}
FILE *
file_open(filename, mode)
char *filename;
char *mode;
/*
* Open the file, die if failure
*/
{
register FILE *fd;
if ((fd = fopen(filename, mode)) == NULL) {
perror(filename);
error("?COOBLD-F-Can't %s \"%s\"\n",
(*mode == 'w') ? "create" : "open", filename);
}
return(fd);
}
maketext(argc, argv)
int argc;
char *argv[];
/*
* Read files obtaining the counts.
*
* Header is set as follows:
*
* header.ncookie Number of cookies (long)
* header.nindex Index dimension
* header.subindex Number of subindex entries
* header.sindex Sizeof index[]
* header.date ctime()
*/
{
register int len;
long subsquare;
char *cpystr();
register int bigbytes; /* Longest record bytes */
int tvec[2];
FILE *infd;
register int nfiles;
int i;
int nrecords;
bigbytes = 0;
time(&tvec);
cpystr(&header.date, ctime(&tvec));
header.ncookie = 0;
header.nindex = 0;
subsquare = 0;
len = 0;
/*
* Read all cookies to count them and get the max. length.
*/
for (i = 1; i < argc; i++) {
if (argv[i] == NULL)
continue;
if ((infd = fwild(argv[i], "r")) == NULL) {
perror(argv[i]);
continue;
}
for (nfiles = 0; fnext(infd); nfiles++) {
fgetname(infd, text);
printf("%s:", text);
nrecords = 0;
while (!feof(infd)) {
fgets(text, sizeof text, infd);
nrecords++;
if (feof(infd)
|| (text[0] == SIGNAL && text[1] == SIGNAL)) {
if (len == 0)
continue;
if (len > bigbytes)
bigbytes = len;
len = 0;
header.ncookie++;
if (subsquare < header.ncookie) {
header.nindex++;
subsquare = header.nindex * header.nindex;
}
}
else {
len += strlen(text) + 2;
}
}
printf("\t%d\n", nrecords);
}
if (nfiles == 0) {
printf("No files match \"%s\"\n", argv[i]);
}
}
header.subindex = (header.ncookie + header.nindex - 1) / header.nindex;
header.sindex = header.nindex * sizeof (long);
printf("%ld cookies read, the longest has %d bytes\n",
header.ncookie, bigbytes);
printf("top index = %d, sub index = %d, index area size = %d\n",
header.nindex, header.subindex, header.sindex);
}
makedummy(argc, argv)
int argc;
char *argv[];
/*
* Build a dummy cookie file in two separate files:
* dummyfp Gets the cookie data
* indexfp Gets the indices.
*
* This way, we don't have to reposition the file, nor do we
* have to read and write the same file.
*/
{
register int subi; /* Index into sub_index[] */
register int topi; /* Index into top_index[] */
register int len; /* Input record length */
int i;
FILE *infd;
long count;
long dummy_loc;
count = 0;
if ((top_index = calloc(header.sindex, 1)) == NULL
|| (sub_index = calloc(header.sindex, 1)) == NULL)
error("Can't allocate index buffers -- %d bytes\n", header.sindex);
put(&header, sizeof header, dummyfp, "dummy header");
put(&header, sizeof header, indexfp, "index header");
put(sub_index, header.sindex, dummyfp, "dummy top index");
put(sub_index, header.sindex, indexfp, "index top index");
firstindex = ftell(indexfp);
for (subi = header.subindex; --subi >= 0;) {
put(sub_index, header.sindex, dummyfp, "dummy sub index");
}
dummy_loc = firstcookie = ftell(dummyfp);
subi = 0;
topi = 0;
len = 0;
for (i = 1; i < argc; i++) {
if (argv[i] == NULL)
continue;
if ((infd = fwild(argv[i], "r")) == NULL)
continue;
while (fnext(infd) != NULL) {
while (!feof(infd)) {
if (fgets(text, sizeof text, infd) == NULL
|| (text[0] == '%' && text[1] == '%')) {
if (len == 0)
continue;
len = 0;
count++;
if (subi >= header.nindex) {
if (topi >= header.nindex) {
error("Too many cookies, max is %d ** 2\n",
header.nindex);
}
top_index[topi] = ftell(indexfp);
topi++;
put(sub_index, header.sindex, indexfp, "sub index");
subi = 0;
}
sub_index[subi] = dummy_loc;
subi++;
#ifdef rsx
fput("%%\n", 4, dummyfp);
#else
fputs("%%\n", dummyfp);
#endif
dummy_loc = ftell(dummyfp);
}
else {
#ifdef rsx
fput(text, strlen(text) + 1, dummyfp);
#else
fputs(text, dummyfp);
#endif
len += strlen(text);
}
if (ferror(dummyfp)) {
perror("writing text to temp file");
error("Output error");
}
}
}
}
/*
* Put the last subindex record
*/
while (subi < header.nindex) {
sub_index[subi] = -1;
subi++;
}
top_index[topi] = ftell(indexfp);
topi++;
put(sub_index, header.sindex, indexfp, "last sub index");
while (topi < header.nindex) {
top_index[topi] = -1;
topi++;
}
printf("Work files built, %ld cookies, %d index levels\n",
count, header.nindex);
if (count != header.ncookie)
error("Expected %ld cookies, read %ld\n", header.ncookie, count);
}
makecookie()
/*
* Write outfp with cookie file, using
*
* indexfp Index file (has sub-indexes)
* dummyfp Cookie work file
*
*/
{
register int i;
register int bytect;
long itemct;
put(&header, sizeof header, outfp, "cookie header");
put(top_index, header.sindex, outfp, "cookie top index");
itemct = 0;
if (fseek(indexfp, firstindex, 0) != 0)
error("Can't seek to %ld on index file\n", firstindex);
if (fseek(dummyfp, firstcookie, 0) != 0)
error("Can't seek to %ld on cookie file\n", firstcookie);
for (i = 0; i < header.subindex; i++) {
get(sub_index, header.sindex, indexfp, "sub index");
put(sub_index, header.sindex, outfp, "cookie sub index");
}
printf("%d index records written\n", header.nindex + 1);
#ifdef rsx
while (fget(text, sizeof text, dummyfp), !feof(dummyfp)) {
fput(text, strlen(text) + 1, outfp);
#else
while (fgets(text, sizeof text, dummyfp) != NULL) {
fputs(text, outfp);
#endif
}
if (ferror(outfp)) {
perror("writing output");
error("Output error");
}
}
/*
* Raw I/O routines
*/
get(whereto, size, fd, why)
char *whereto; /* Where to read to */
int size; /* Buffer size */
FILE *fd; /* Input file descriptor */
char *why; /* Who is reading for error */
/*
* Read into the buffer. Return the number of bytes read.
* All errors are fatal.
*/
{
register int i;
#ifdef rsx
if ((i = fget(whereto, size, fd)) != size || ferror(fd)) {
perror("coobld fget error");
error("Reading %s, expected %d bytes, read %d bytes\n",
why, size, i);
}
#else
if ((i = fread(whereto, size, 1, fd)) != 1 || ferror(fd)) {
perror("coobld fread error");
error("Reading %s, expected 1 item, %d bytes, read %d items\n",
why, size, i);
}
#endif
}
put(wherefrom, size, fd, why)
char *wherefrom; /* Where to write from */
int size; /* Number of bytes to write */
FILE *fd; /* Output file descriptor */
char *why; /* Who is writeing for error */
/*
* Write from the buffer. All errors are fatal.
*/
{
register int i;
#ifdef rsx
if ((i = fput(wherefrom, size, fd)) != size || ferror(fd)) {
perror("coobld fput error");
error("Error writing %d bytes to %s, %d bytes written\n",
size, why, i);
}
#else
if ((i = fwrite(wherefrom, size, 1, fd)) != 1 || ferror(fd)) {
perror("coobld fwrite error");
error("Error writing 1 item of %d bytes to %s, %d items\n",
size, why, i);
}
#endif
}
/*
* For debugging only
*/
dump(indextable, why)
long indextable[];
char *why;
{
register int i;
printf("\n%s\n", why);
for (i = 0; i < header.nindex; i++)
printf("%3d %ld\n", i, indextable[i]);
}